package com.zatech.cgnci.project.controller;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.zatech.cgnci.project.base.context.UserContext;
import com.zatech.cgnci.project.base.enums.ApprovalConfigEnum;
import com.zatech.cgnci.project.base.enums.BusinessScenariosEnum;
import com.zatech.cgnci.project.base.enums.OperationTypeEnum;
import com.zatech.cgnci.project.base.enums.ResponseCodeEnum;
import com.zatech.cgnci.project.base.exception.GlobalException;
import com.zatech.cgnci.project.base.utils.BeanUtils;
import com.zatech.cgnci.project.base.utils.DateUtils;
import com.zatech.cgnci.project.base.utils.VerifyUtils;
import com.zatech.cgnci.project.dto.*;
import com.zatech.cgnci.project.entity.*;
import com.zatech.cgnci.project.mapper.CgnciApprovalInfoMapper;
import com.zatech.cgnci.project.mapper.CgnciReinsuranceRiskInsuredMapper;
import com.zatech.cgnci.project.service.*;
import com.zatech.cgnci.project.vo.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 承保管理--保单表 前端控制器
 * </p>
 *
 * @author Generator
 * @since 2024-12-20
 */
@Slf4j
@RestController
@RequestMapping("/api/business/insurance")
@RequiredArgsConstructor
@Api(produces = "application/json", tags = "承保管理--保单api接口文档")
public class CgnciBusinessInsuranceController {

    private final CgnciBusinessInsuranceService cgnciBusinessInsuranceService;

    private final CgnciBusinessProjectService cgnciBusinessProjectService;

    private final IApprovalService approvalService;

    private final CgnciApprovalInfoMapper approvalInfoMapper;

    private final CgnciReinsuranceInfoService cgnciReinsuranceInfoService;

    private final CgnciDirectInsuranceRiskService cgnciDirectInsuranceRiskService;

    private final CgnciDirectInsuranceDetailService cgnciDirectInsuranceDetailService;

    private final CgnciReinsuranceRiskService cgnciReinsuranceRiskService;

    private final CgnciReinsuranceRiskInsuredService cgnciReinsuranceRiskInsuredService;

    private final CgnciOperationLogsService cgnciOperationLogsService;

    private final CgnciReInsuranceCompanyService cgnciReInsuranceCompanyService;
    private final CgnciReinsuranceRiskInsuredMapper cgnciReinsuranceRiskInsuredMapper;


    @PostMapping("/page")
    @ApiOperation(value = "分页列表查询")
    public IPage<CgnciBusinessInsurancePageVO> page(@RequestBody CgnciBusinessInsuranceQueryDTO queryDTO) {
        queryDTO.setBusinessType("1");
        return cgnciBusinessInsuranceService.pageBusinessInsurance(queryDTO);
    }

    @GetMapping("/detail")
    @ApiOperation(value = "详情")
    public CgnciBusinessInsuranceMainVO detail(@RequestParam(value = "insuranceId") @NotNull(message = "insuranceId不能为空") Long insuranceId) {
        return cgnciBusinessInsuranceService.detail(insuranceId, "1");
    }

    @GetMapping("/getPolicyInfo")
    @ApiOperation(value = "根据保单号查询保单信息")
    public CgnciBusinessInsuranceMainVO getPolicyInfo(@RequestParam(value = "policyNo") @NotBlank(message = "policyNo不能为空") String policyNo) {
        return cgnciBusinessInsuranceService.getPolicyInfo(policyNo);
    }

    @PostMapping("/check/reinsurerFocus")
    @ApiOperation(value = "校验是否触发再保人集中度")
    public CheckReinsurerFocusVO reinsurerFocus(@RequestBody CheckReinsurerFocusDTO checkReinsurerFocusDTO) {
        CheckReinsurerFocusVO reinsurerFocusVO = CheckReinsurerFocusVO.builder().checkReinsurerFocus(false).reinsurerName(null).build();
        // 判断流程是否触发再保人集中度规则
        // 总分出限额
        BigDecimal totalCededLimit = BigDecimal.ZERO;
        List<CheckReinsurerFocusDTO.CgnciReinsuranceRiskCheckDTO> risks = checkReinsurerFocusDTO.getRisks();
        for (CheckReinsurerFocusDTO.CgnciReinsuranceRiskCheckDTO risk : risks) {
            List<CheckReinsurerFocusDTO.CgnciReinsuranceRiskLayerCheckDTO> riskLayers = risk.getRiskLayers();
            BigDecimal cededLimit = BeanUtils.sumBigDecimalProperty(riskLayers, CheckReinsurerFocusDTO.CgnciReinsuranceRiskLayerCheckDTO::getCededLimit);
            totalCededLimit = totalCededLimit.add(cededLimit);
        }

        // 再保人分出限额
        BigDecimal oneCededLimit = BigDecimal.ZERO;
        List<CheckReinsurerFocusDTO.CgnciReinsurerCheckDTO> reinsurers = checkReinsurerFocusDTO.getReinsurers();
        for (CheckReinsurerFocusDTO.CgnciReinsurerCheckDTO reinsurer : reinsurers) {
            List<CheckReinsurerFocusDTO.CgnciReinsuranceRiskCheckDTO> risks1 = reinsurer.getRisks();
            for (CheckReinsurerFocusDTO.CgnciReinsuranceRiskCheckDTO risk1 : risks1) {
                List<CheckReinsurerFocusDTO.CgnciReinsuranceRiskLayerCheckDTO> riskLayers = risk1.getRiskLayers();
                BigDecimal cededLimit = BeanUtils.sumBigDecimalProperty(riskLayers, CheckReinsurerFocusDTO.CgnciReinsuranceRiskLayerCheckDTO::getCededLimit);
                oneCededLimit = oneCededLimit.add(cededLimit);
            }
            BigDecimal rate = oneCededLimit.divide(totalCededLimit, 4, RoundingMode.DOWN).multiply(new BigDecimal(100));
            // 再保人集中度规则：对于单一再保险人在单一再保合同承接的分出保额如果在总分出保额的60%或 2 亿人民币以,触发流程变更
            if (rate.compareTo(new BigDecimal(60)) >= 0 || oneCededLimit.compareTo(new BigDecimal(200000000)) >= 0) {
                reinsurerFocusVO.setCheckReinsurerFocus(true);
                // 避免反射型XXS风险
                CgnciReInsuranceCompanyDO reInsuranceCompanyDO = cgnciReInsuranceCompanyService.getOne(new LambdaQueryWrapper<CgnciReInsuranceCompanyDO>()
                        .eq(CgnciReInsuranceCompanyDO::getCompanyCode, reinsurer.getReinsurerCode()));
                reinsurerFocusVO.setReinsurerName(reInsuranceCompanyDO.getCompanyNameCn());
                return reinsurerFocusVO;
            }
        }
        return reinsurerFocusVO;
    }

    @PostMapping("/check/specialColumn")
    @ApiOperation(value = "校验是否触发特殊字段修改")
    public CheckSpecialColumnVO specialColumn(@RequestBody @Valid CheckSpecialColumnDTO checkSpecialColumnDTO) {
        CheckSpecialColumnVO specialColumnVO = CheckSpecialColumnVO.builder().checkSpecialColumn(false).build();
        // 查询项目起期，止期
        CgnciBusinessProjectDO businessProjectDO = cgnciBusinessProjectService.getById(checkSpecialColumnDTO.getProjectId());
        if (VerifyUtils.isEmpty(businessProjectDO)) {
            throw new GlobalException(ResponseCodeEnum.HTTP_REQUEST_SERVICE_ERROR);
        }

        // 查询分入信息-总再保手续费率
        CgnciReinsuranceInfoDO divideInDO = cgnciReinsuranceInfoService.getOne(new LambdaQueryWrapper<CgnciReinsuranceInfoDO>()
                .eq(CgnciReinsuranceInfoDO::getBusinessId, checkSpecialColumnDTO.getProjectId()).eq(CgnciReinsuranceInfoDO::getReinsuranceType, 1));
        // 临分分出信息-总再保手续费率
        CgnciReinsuranceInfoDO divideOutDO = cgnciReinsuranceInfoService.getOne(new LambdaQueryWrapper<CgnciReinsuranceInfoDO>()
                .eq(CgnciReinsuranceInfoDO::getBusinessId, checkSpecialColumnDTO.getProjectId()).eq(CgnciReinsuranceInfoDO::getReinsuranceType, 3));

        // 校验是否修改了起保日期
        if (!DateUtils.areDatesEqual(businessProjectDO.getStartDate(), checkSpecialColumnDTO.getStartDate())) {
            specialColumnVO.setCheckSpecialColumn(true);
            return specialColumnVO;
        }
        // 校验是否修改了终保日期
        if (!DateUtils.areDatesEqual(businessProjectDO.getEndDate(), checkSpecialColumnDTO.getEndDate())) {
            specialColumnVO.setCheckSpecialColumn(true);
            return specialColumnVO;
        }

        // 校验分入信息-总再保手续费率是否超过项目设置的分入信息-总再保手续费率
        if (VerifyUtils.isNotEmpty(checkSpecialColumnDTO.getDivideInTotalBrokerCommissionRate()) && VerifyUtils.isNotEmpty(divideOutDO.getTotalBrokerCommissionRate())) {
            if (checkSpecialColumnDTO.getDivideInTotalBrokerCommissionRate().compareTo(divideInDO.getTotalBrokerCommissionRate()) > 0) {
                specialColumnVO.setCheckSpecialColumn(true);
                return specialColumnVO;
            }
        }
        // 校验临分分出信息-总再保手续费率是否超过项目设置的临分分出信息-总再保手续费率
        if (VerifyUtils.isNotEmpty(checkSpecialColumnDTO.getDivideOutTotalBrokerCommissionRate()) && VerifyUtils.isNotEmpty(divideOutDO.getTotalBrokerCommissionRate())) {
            if (checkSpecialColumnDTO.getDivideOutTotalBrokerCommissionRate().compareTo(divideOutDO.getTotalBrokerCommissionRate()) > 0) {
                specialColumnVO.setCheckSpecialColumn(true);
                return specialColumnVO;
            }
        }
        return specialColumnVO;
    }


    @PostMapping("/next/project/create")
    @ApiOperation(value = "新建保单-新保单")
    @Transactional(rollbackFor = Exception.class)
    public Long nextProjectCreate(@RequestBody @Valid CgnciBusinessInsuranceNextCreateDTO addCreateDTO) {
        // 获取当前登录用户
        UserEntity user = UserContext.getUser();
        CgnciBusinessInsuranceDO businessInsuranceDO = cgnciBusinessInsuranceService.nextProjectCreate(addCreateDTO);

        // 创建任务,绑定工作流formId. 并且关联工作台的跳转地址url以及参数
        ApprovalInfoVO approvalInfoVO = approvalService.create(FlowTaskCreateDTO.builder().approvalConfigGroupId(ApprovalConfigEnum.APPROVAL_CONFIG_007.getGroupId()).formId(String.valueOf(businessInsuranceDO.getInsuranceId())).formNo(businessInsuranceDO.getFormNo())
                .redirectionUrl(ApprovalConfigEnum.APPROVAL_CONFIG_007.getRedirectionUrl()).redirectionParam(String.valueOf(businessInsuranceDO.getInsuranceId())).redirectionDesc(ApprovalConfigEnum.APPROVAL_CONFIG_007.getRedirectionDesc()).build());
        //插入操作日志
        cgnciOperationLogsService.insertOperationLogs(
                String.valueOf(businessInsuranceDO.getInsuranceId()),
                BusinessScenariosEnum.POLICY.getCode(),
                OperationTypeEnum.ENTRY_POLICY.getCode(),
                "保单录入任务号：" + approvalInfoVO.getTaskId(),
                user.getNameAndCode()
        );
        return businessInsuranceDO.getInsuranceId();
    }


    @PostMapping("/next/insurance/create")
    @ApiOperation(value = "新建保单-续保保单")
    @Transactional(rollbackFor = Exception.class)
    public Long nextInsuranceCreate(@RequestBody @Valid CgnciBusinessInsuranceNextCreateDTO addCreateDTO) {
        // 获取当前登录用户
        UserEntity user = UserContext.getUser();
        CgnciBusinessInsuranceDO businessInsuranceDO = cgnciBusinessInsuranceService.nextInsuranceCreate(addCreateDTO);

        // 创建任务,绑定工作流formId. 并且关联工作台的跳转地址url以及参数
        ApprovalInfoVO approvalInfoVO = approvalService.create(FlowTaskCreateDTO.builder().approvalConfigGroupId("007").formId(String.valueOf(businessInsuranceDO.getInsuranceId())).formNo(businessInsuranceDO.getFormNo())
                .redirectionUrl("/cgnci/api/business/insurance/detail").redirectionParam(String.valueOf(businessInsuranceDO.getInsuranceId())).redirectionDesc("跳转保单详情").build());
        //插入操作日志
        cgnciOperationLogsService.insertOperationLogs(
                String.valueOf(businessInsuranceDO.getInsuranceId()),
                BusinessScenariosEnum.POLICY.getCode(),
                OperationTypeEnum.ENTRY_POLICY.getCode(),
                "保单录入任务号：" + approvalInfoVO.getTaskId(),
                user.getNameAndCode()
        );
        return businessInsuranceDO.getInsuranceId();
    }

    @PostMapping("/saveOrUpdate")
    @ApiOperation(value = "新增或者修改")
    @Transactional(rollbackFor = Exception.class)
    public void saveOrUpdate(@RequestBody @Valid CgnciBusinessInsuranceSaveOrUpdateDTO updateDTO) {
        CgnciBusinessInsuranceDO businessInsurance = cgnciBusinessInsuranceService.saveOrUpdateBusinessInsurance(updateDTO, "1");

        // 维护业务名称到工作台
        CgnciApprovalInfoDO approvalInfoDO = approvalInfoMapper.selectOne(new LambdaQueryWrapper<CgnciApprovalInfoDO>()
                .eq(CgnciApprovalInfoDO::getFormId, updateDTO.getBusinessInsuranceUpdateDTO().getInsuranceId()));
        if (VerifyUtils.isEmpty(approvalInfoDO)) {
            throw new GlobalException(ResponseCodeEnum.HTTP_REQUEST_SERVICE_ERROR, "任务流程不存在");
        }
        approvalInfoDO.setBusinessName(updateDTO.getBusinessInsuranceUpdateDTO().getProjectName());
        approvalInfoMapper.updateById(approvalInfoDO);

        // 提交审核
        if (VerifyUtils.isNotEmpty(updateDTO.getFlowTaskType()) && "submit".equals(updateDTO.getFlowTaskType())) {
            // 触发再保人集中度规则&倒签规则>触发再保人集中度规则>触发倒签>特殊字段修改审批>默认流程
            String groupId = getGroupId(updateDTO.getCheckReinsurerFocus(), updateDTO.getCheckSpecialColumn(), businessInsurance.getCreateTime(), updateDTO.getBusinessInsuranceUpdateDTO().getStartDate());
            if (VerifyUtils.isNotEmpty(groupId)) {
                approvalInfoMapper.updateById(CgnciApprovalInfoDO.builder().approvalInfoId(updateDTO.getApprovalInfoId()).approvalConfigGroupId(groupId).build());
            }
            cgnciBusinessInsuranceService.submit(FlowTaskSubmitDTO.builder().approvalInfoId(updateDTO.getApprovalInfoId()).formId(String.valueOf(businessInsurance.getInsuranceId())).build());
        }
    }


    @PostMapping("/approve")
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "审核流程任务")
    public void approve(@RequestBody @Valid FlowTaskApprovalDTO flowTaskDTO) {
        cgnciBusinessInsuranceService.approve(flowTaskDTO);
    }

    @GetMapping("/listBackNode")
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "获取退回流程节点")
    public List<ApprovalConfigVO> listBackNode(@RequestParam(value = "insuranceId") @NotNull(message = "insuranceId不能为空") Long insuranceId) {
        CgnciBusinessInsuranceDO businessInsuranceDO = cgnciBusinessInsuranceService.getById(insuranceId);
        return approvalService.listBackNode(String.valueOf(businessInsuranceDO.getInsuranceId()), businessInsuranceDO.getFormNo());
    }

    @PostMapping("/back")
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "退回流程任务")
    public void back(@RequestBody @Valid FlowTaskBackDTO flowTaskDTO) {
        cgnciBusinessInsuranceService.back(flowTaskDTO);
    }

    @GetMapping("/signOut")
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "注销")
    public void signOut(@RequestParam(value = "insuranceId") @NotNull(message = "insuranceId不能为空") Long insuranceId) {
        cgnciBusinessInsuranceService.signOut(insuranceId);
    }

    @GetMapping("/log")
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "获取操作日志")
    public List<ApprovalRecordVO> log(@RequestParam(value = "insuranceId") @NotNull(message = "insuranceId不能为空") Long insuranceId) {
        return cgnciBusinessInsuranceService.log(insuranceId);
    }

    @GetMapping("/getInsuranceClaim")
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "根据保单号查询分入分出信息")
    public CgnciBusinessInsuranceClaimVO getInsuranceClaim(@RequestParam(value = "policyNo") @NotNull(message = "policyNo不能为空") String policyNo,
                                                           @RequestParam(value = "caseNo") @NotNull(message = "caseNo不能为空") String caseNo) {
        return cgnciBusinessInsuranceService.getInsuranceClaim(policyNo, caseNo);
    }

    @GetMapping("/insuranceRisk/deleteById")
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "删除直保险种")
    public void deleteInsuranceRiskById(@RequestParam(value = "riskId") Long riskId) {
        cgnciDirectInsuranceRiskService.deleteInsuranceRisk(riskId, "2");
    }

    @GetMapping("/insuranceRisk/deleteByIds")
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "批量删除直保险种")
    public void deleteInsuranceRiskByIds(@RequestParam(value = "riskIds") String riskIds) {
        List<Long> idList = Arrays.stream(riskIds.split(",")).map(Long::valueOf).collect(Collectors.toList());
        idList.forEach(id -> cgnciDirectInsuranceRiskService.deleteInsuranceRisk(id, "2"));
    }

    @GetMapping("/insuranceDetail/deleteById")
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "删除直保标的明细")
    public void deleteInsuranceDetailById(@RequestParam(value = "detailId") Long detailId) {
        cgnciDirectInsuranceDetailService.deleteInsuranceDetail(detailId, "2");
    }

    @GetMapping("/insuranceDetail/deleteByIds")
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "批量删除直保标的明细")
    public void deleteInsuranceDetailByIds(@RequestParam(value = "detailIds") String detailIds) {
        List<Long> idList = Arrays.stream(detailIds.split(",")).map(Long::valueOf).collect(Collectors.toList());
        idList.forEach(id -> cgnciDirectInsuranceDetailService.deleteInsuranceDetail(id, "2"));
    }

    @GetMapping("/reinsuranceRisk/deleteById")
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "删除分入分出险种")
    public void deleteReinsuranceRiskById(@RequestParam(value = "reinsuranceRiskId") @ApiParam(value = "reinsuranceRiskId") Long reinsuranceRiskId,
                                                @RequestParam(value = "type") @ApiParam(value = "删除模块(1-分入险种,2-分出险种,3-分入方案/再保人险种)") String type) {
        cgnciReinsuranceRiskService.deleteReinsuranceRiskForBusiness(reinsuranceRiskId, type);
    }

    @GetMapping("/reinsuranceRisk/deleteByIds")
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "批量删除分入分出险种")
    public void deleteReinsuranceRiskByIds(@RequestParam(value = "reinsuranceRiskIds") @ApiParam(value = "reinsuranceRiskIds") String reinsuranceRiskIds,
                                                 @RequestParam(value = "type") @ApiParam(value = "删除模块(1-分入险种,2-分出险种,3-分入方案/再保人险种)") String type) {
        List<Long> idList = Arrays.stream(reinsuranceRiskIds.split(",")).map(Long::valueOf).collect(Collectors.toList());
        idList.forEach(id -> cgnciReinsuranceRiskService.deleteReinsuranceRiskForBusiness(id, type));
    }

    @GetMapping("/reinsuranceRiskInsured/deleteById")
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "删除分入分出险种标的")
    public void deleteReinsuranceRiskInsuredById(@RequestParam(value = "riskInsuredId") @ApiParam(value = "riskInsuredId") Long riskInsuredId,
                                                @RequestParam(value = "type") @ApiParam(value = "删除模块(1-分入险种,2-分出险种,3-分入方案/再保人险种)") String type) {
        cgnciReinsuranceRiskInsuredService.deleteReinsuranceRiskInsuredForBusiness(riskInsuredId, type);
    }

    @GetMapping("/reinsuranceRiskInsured/deleteByIds")
    @Transactional(rollbackFor = Exception.class)
    @ApiOperation(value = "批量删除分入分出险种标的")
    public void deleteReinsuranceRiskInsuredByIds(@RequestParam(value = "riskInsuredIds") @ApiParam(value = "riskInsuredIds") String riskInsuredIds,
                                                 @RequestParam(value = "type") @ApiParam(value = "删除模块(1-分入险种,2-分出险种,3-分入方案/再保人险种)") String type) {
        List<Long> idList = Arrays.stream(riskInsuredIds.split(",")).map(Long::valueOf).collect(Collectors.toList());
        idList.forEach(id -> cgnciReinsuranceRiskInsuredService.deleteReinsuranceRiskInsuredForBusiness(id, type));
    }

    private String getGroupId(Boolean checkReinsurerFocus, Boolean checkSpecialColumn, Date createTime, Date startDate) {
        if (VerifyUtils.isNotEmpty(checkReinsurerFocus) && checkReinsurerFocus) {
            if (createTime.after(DateUtils.getTimeByType(startDate, "start"))) {
                return ApprovalConfigEnum.APPROVAL_CONFIG_017.getGroupId();
            }
            return ApprovalConfigEnum.APPROVAL_CONFIG_008.getGroupId();
        } else {
            if (createTime.after(DateUtils.getTimeByType(startDate, "start"))) {
                return ApprovalConfigEnum.APPROVAL_CONFIG_019.getGroupId();
            } else if (VerifyUtils.isNotEmpty(checkSpecialColumn) && checkSpecialColumn) {
                return ApprovalConfigEnum.APPROVAL_CONFIG_018.getGroupId();
            }
        }
        return null;
    }

}

